import asyncio
import re
from typing import Any, List

from aiohttp.client import ClientSession

from app.bot.utils.logger import log

from .schemas import EmailMessage
from .utils import TempMailException, check_response


class Dropmail:
    def __init__(
        self,
        token: str,
    ) -> None:
        self.session = ClientSession()
        self.session.headers.update(
            {
                "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:105.0) Gecko/20100101 Firefox/105.0",
                "Content-Type": "application/json",
            }
        )
        self.token = token

    @check_response()
    async def _make_request(self, method: str, url: str, **kwargs) -> dict:
        try:
            async with await self.session.request(method, url, **kwargs) as response:
                return await response.json(content_type=None)
        except Exception as e:
            raise TempMailException(type(e).__name__, str(e))

    async def create_mail_box(self) -> str | None:
        """Получаем адрес почты"""

        data = {
            "query": "mutation {introduceSession {id, expiresAt, addresses {address}}}",
        }
        response = await self._make_request(
            "post", f"https://dropmail.me/api/graphql/{self.token}", json=data
        )
        try:
            email_address = response["data"]["introduceSession"]["addresses"][0][
                "address"
            ]
        except (IndexError, KeyError, TypeError):
            log.info(
                f"Не удалось получить временную почту. JSON ответ сервера: {response}"
            )
            email_address = None

        return email_address

    async def get_mails_list(self) -> List[EmailMessage]:
        data = {
            "query": "query {sessions {id, expiresAt, mails {rawSize, fromAddr, toAddr, downloadUrl, text, headerSubject}}}",
        }
        response = await self._make_request(
            "post", f"https://dropmail.me/api/graphql/{self.token}", json=data
        )
        sessions = response["data"]["sessions"]
        emails = []
        for s in sessions:
            mails = s["mails"]
            for m in mails:
                emails.append(
                    EmailMessage(
                        m.get("fromAddr"),
                        m.get("toAddr"),
                        m.get("headerSubject"),
                        m.get("text"),
                    )
                )
        return emails

    async def get_code_from_temp_mail(self) -> bool | Any:
        """Получаем код с временной почты"""

        retries = 0
        log.info("Жду код с временной почты")
        while True:
            await asyncio.sleep(5)
            emails = await self.get_mails_list()
            if len(emails) == 0:
                log.info("Пока нет писем на этом адресе")
            for mail in emails:
                if "Let's verify" in mail.subject:
                    letter_body = mail.full_text.replace(" ", "")
                    code_result = re.findall(r"(\d{6,})", letter_body)
                    log.info("Код получен")
                    return code_result[0]
            retries += 1
            if retries > 10:
                log.error(f"Не смог получить код после {retries} попыток")
                return False
            return False
